package com.mxchip.livestarmobile.mobile.ui.call

import android.app.Application
import android.os.Looper
import androidx.lifecycle.*
import com.mxchip.livestarmobile.mobile.util.Log.FileLog
import com.mxchip.livestarmobile.mobile.util.Log.MyLog
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.functions.Consumer
import io.reactivex.subjects.PublishSubject
import java.text.SimpleDateFormat
import java.util.*


class DbyViewModel(application: Application) : AndroidViewModel(application) {
    private val logger: FileLog = FileLog.getLogger(DbyViewModel::class.java)
    private val avRepository = AVRepository
    val userIds = avRepository.userIds

    fun userAdd(uid: String) {
        avRepository.addUserId(uid)
    }

    fun userRemove(uid: String) {
        avRepository.removeUserId(uid)
    }

    val audioList = avRepository.micUserIds

    fun audioAdd(uid: String) {
        avRepository.addMicUserId(uid)
    }

    fun audioRemove(uid: String) {
        avRepository.removeMicUserId(uid)
    }

    val _broadcast: MutableLiveData<String> = MutableLiveData()

    val broadcast: LiveData<String>
        get() = _broadcast

    fun broadcast(value: String) {
        _broadcast.value = value
    }

    private val _videoResInitFinish = MutableLiveData<Boolean>(false)

    val videoResInitFinish: LiveData<Boolean>
        get() = _videoResInitFinish

    fun videoResInitFinish(value: Boolean) {
        _videoResInitFinish.postValue(value)
    }


    private val _camera = MutableLiveData<Boolean>(false)

    val camera: LiveData<Boolean>
        get() = _camera

    fun camera(value: Boolean) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            _camera.value = value
        } else {
            _camera.postValue(value)
        }
    }


    private val _mic by lazy { MutableLiveData<Boolean>(false) }

    val mic: LiveData<Boolean>
        get() = _mic

    fun mic(value: Boolean) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            _mic.value = value
        } else {
            _mic.postValue(value)
        }
    }


    private val _callControlTouched: MutableLiveData<Boolean> = MutableLiveData(false)
    val callControlTouched: LiveData<Boolean>
        get() = _callControlTouched

    fun CallControlTouched() {
        _callControlTouched.value = !_callControlTouched.value!!
    }

    private val _showRemoteResView: MutableLiveData<Boolean> = MutableLiveData(false)

    val showRemoteResView: LiveData<Boolean>
        get() = _showRemoteResView

    fun showRemoteResView(value: Boolean) {
        _showRemoteResView.value = value
    }

    private val compositeDisposable: CompositeDisposable by lazy {
        CompositeDisposable()
    }

    private val sendAVPacketSubject: PublishSubject<AVPacket> by lazy {
        PublishSubject.create<AVPacket>()
    }

    private val receiveAVPacketSubject: PublishSubject<AVPacket> by lazy {
        PublishSubject.create<AVPacket>()
    }
    private val sendAudioPacketSubject: PublishSubject<AVPacket> by lazy {
        PublishSubject.create<AVPacket>()
    }


    private val roomId = MutableLiveData<String?>()

    val avDevices = AVRepository.avDevices
    val mIsEnter = AVRepository.mIsEnter

    override fun onCleared() {
        compositeDisposable.clear()
        avRepository.clear()
    }

    fun addAVDevice(device: AVDevice) {
        avRepository.addAVDevice(device)
    }

    fun resetDevices(device: List<AVDevice>) {
        avRepository.resetDevices(device)
    }

    fun removeAVDevice(uid: String, deviceName: String) {
        avRepository.removeAVDevice(uid, deviceName)
    }

    fun removeAVDevice(uid: String) {
        avRepository.removeAVDevice(uid)
    }

    fun join(): LiveData<String?> {
        return roomId
    }

    fun join(id: String?) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            roomId.value = id
        } else {
            roomId.postValue(id)
        }
    }

    fun postJoin(id: String?) {
        roomId.postValue(id)
    }

    fun enterAfterJoined() {
        avRepository.enterAfterJoined()
    }


    val _netQuality: MutableLiveData<String> = MutableLiveData()

    val netQuality: LiveData<String>
        get() = _netQuality

    fun netQuality(value: String) {
        _netQuality.postValue(value)
    }

    //-------------------------video-----------------------------
    fun sendAVPacketConsumer(consumer: Consumer<AVPacket>): Disposable {
        val disposable = sendAVPacketSubject.subscribe(consumer)
        compositeDisposable.add(disposable)
        return disposable
    }


    fun sendAVPacket(avPacket: AVPacket) {
        sendAVPacketSubject.onNext(avPacket)
    }

    fun receiveAVPacketConsumer(consumer: Consumer<AVPacket>): Disposable {
        val disposable = receiveAVPacketSubject.subscribe(consumer, Consumer<Any> {
            logger.error(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) +
                    " receiveAVPacketConsumer" + it)
        })
        compositeDisposable.add(disposable)
        return disposable
    }

    fun receiveAVPacket(avPacket: AVPacket) {
        receiveAVPacketSubject.onNext(avPacket)
    }

    //-------------------------audio-----------------------------
    fun sendAudioPacketConsumer(consumer: Consumer<AVPacket>): Disposable {
        val disposable = sendAudioPacketSubject.subscribe(consumer)
        compositeDisposable.add(disposable)
        return disposable
    }

    fun sendAudioPacket(avPacket: AVPacket) {
        sendAudioPacketSubject.onNext(avPacket)
    }

}

data class AVDevice(val uid: String, val deviceName: String) {
    companion object {
        const val CAMERA_LOCAL = "frontCameraHD"
        const val CAMERA_LOCAL_SMALL = ""
        const val CAMERA_HDMI = "hdmi"
        const val CAMERA_WIFI = "cameraWifi"
        const val AUDIO_BUILD_IN = "audioBuildIn"
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as AVDevice

        if (uid != other.uid) return false
        if (deviceName != other.deviceName) return false

        return true
    }

    override fun hashCode(): Int {
        var result = uid.hashCode()
        result = 31 * result + deviceName.hashCode()
        return result
    }

}

data class AVPacket(val data: ByteArray, val deviceName: String, val uid: String, val format: Int = 0, val width: Int = 0, val height: Int = 0, val rotation: Int = 0, val timestamp: Long = 0) {

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as AVPacket

        if (!data.contentEquals(other.data)) return false
        if (deviceName != other.deviceName) return false
        if (uid != other.uid) return false
        if (format != other.format) return false
        if (width != other.width) return false
        if (height != other.height) return false
        if (rotation != other.rotation) return false
        if (timestamp != other.timestamp) return false

        return true
    }

    override fun hashCode(): Int {
        var result = data.contentHashCode()
        result = 31 * result + deviceName.hashCode()
        result = 31 * result + uid.hashCode()
        result = 31 * result + format
        result = 31 * result + width
        result = 31 * result + height
        result = 31 * result + rotation
        result = 31 * result + timestamp.hashCode()
        return result
    }

}